package com.jackstraw.jack_base.datasource.jpa.base.dao.database;

import com.jackstraw.jack_base.datasource.jpa.base.entity.Query;
import com.jackstraw.jack_base.datasource.jpa.base.entity.po.JpaPo;
import com.jackstraw.jack_base.util.BeanUtil;
import com.jackstraw.jack_base.util.ObjectUtil;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.Selection;
import java.util.ArrayList;
import java.util.List;


public class SimpleJpaDao<PO extends ID, ID extends JpaPo<PO, ID>> extends SimpleJpaRepository<PO, ID> implements JpaDao<PO, ID> {


    private final EntityManager entityManager;

    public SimpleJpaDao(JpaEntityInformation<PO, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    public SimpleJpaDao(Class<PO> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
    }

    @Override
    public EntityManager entityManager() {
        return this.entityManager;
    }

    @Override
    public <PO> PO update(PO entity) {
        PO merge = this.entityManager().merge(entity);
        BeanUtil.copyPublicProperties(merge, entity);
        return entity;
    }

    @Override
    public <PO> List<PO> updateAll(Iterable<PO> entities) {
        Assert.notNull(entities, "Entities must not be null!");
        List<PO> result = new ArrayList<>();
        for (PO entity : entities) {
            result.add(update(entity));
        }
        return result;
    }

    @Override
    public <PO> Long countByQuery(Query<PO> query) {
        Selection selection = query.getCriteriaQuery().getSelection();
        query.getCriteriaQuery().select(query.getCriteriaBuilder().count(query.getFrom()));
        Long count = (Long) this.entityManager().createQuery(query.newCriteriaQuery()).getResultList().get(0);
        query.getCriteriaQuery().select(selection);
        return count;
    }

    @Override
    public <PO> List<PO> query(Query<PO> query) {
        TypedQuery typedQuery = this.entityManager().createQuery(query.newCriteriaQuery()).setFirstResult(query.getIndex());
        if (ObjectUtil.ObjectUtilByLang3.isNotEmpty(query.getPageSize())) {
            typedQuery.setMaxResults(query.getPageSize());
        }
        return typedQuery.getResultList();
    }
}
